const dgram = require('dgram')
const url = require('url')

const messageBuilder = require('./messageBuilder')

let timer = null
let reqTimes = 0
const trackerList = [
  'udp://6ahddutb1ucc3cp.ru:6969/announce',
  'udp://9.rarbg.com:2810/announce',
  'udp://aarsen.me:6969/announce',
  'udp://acxx.de:6969/announce',
  'udp://aegir.sexy:6969/announce',
  'udp://astrr.ru:6969/announce',
  'udp://bedro.cloud:6969/announce',
  'udp://bt.ktrackers.com:6666/announce',
  'udp://bt1.archive.org:6969/announce',
  'udp://epider.me:6969/announce',
  'udp://exodus.desync.com:6969/announce',
  'udp://fe.dealclub.de:6969/announce',
  'udp://htz3.noho.st:6969/announce',
  'udp://ipv4.tracker.harry.lu:80/announce',
  'udp://ipv6.tracker.monitorit4.me:6969/announce',
  'udp://laze.cc:6969/announce',
  'udp://mail.artixlinux.org:6969/announce',
  'udp://mirror.aptus.co.tz:6969/announce',
  'udp://moonburrow.club:6969/announce',
  'udp://movies.zsw.ca:6969/announce',
  'udp://new-line.net:6969/announce',
  'udp://open.4ever.tk:6969/announce',
  'udp://open.demonii.com:1337/announce',
  'udp://open.dstud.io:6969/announce',
  'udp://open.publictracker.xyz:6969/announce',
  'udp://open.stealth.si:80/announce',
  'udp://open.tracker.cl:1337/announce',
  'udp://open.tracker.ink:6969/announce',
  'udp://opentor.org:2710/announce',
  'udp://opentracker.i2p.rocks:6969/announce',
  'udp://opentracker.io:6969/announce',
  'udp://p4p.arenabg.com:1337/announce',
  'udp://private.anonseed.com:6969/announce',
  'udp://retracker01-msk-virt.corbina.net:80/announce',
  'udp://slicie.icon256.com:8000/announce',
  'udp://static.54.161.216.95.clients.your-server.de:6969/announce',
  'udp://t.133335.xyz:6969/announce',
  'udp://thagoat.rocks:6969/announce',
  'udp://thetracker.org:80/announce',
  'udp://torrents.artixlinux.org:6969/announce',
  'udp://tracker.4.babico.name.tr:3131/announce',
  'udp://tracker.altrosky.nl:6969/announce',
  'udp://tracker.arcbox.cc:6969/announce',
  'udp://tracker.artixlinux.org:6969/announce',
  'udp://tracker.auctor.tv:6969/announce',
  'udp://tracker.beeimg.com:6969/announce',
  'udp://tracker.birkenwald.de:6969/announce',
  'udp://tracker.bitsearch.to:1337/announce',
  'udp://tracker.ccp.ovh:6969/announce',
  'udp://tracker.cyberia.is:6969/announce',
  'udp://tracker.dler.com:6969/announce',
  'udp://tracker.doko.moe:6969/announce',
  'udp://tracker.filemail.com:6969/announce',
  'udp://tracker.joybomb.tw:6969/announce',
  'udp://tracker.leech.ie:1337/announce',
  'udp://tracker.moeking.me:6969/announce',
  'udp://tracker.monitorit4.me:6969/announce',
  'udp://tracker.openbittorrent.com:6969/announce',
  'udp://tracker.opentrackr.org:1337/announce',
  'udp://tracker.pimpmyworld.to:6969/announce',
  'udp://tracker.skyts.net:6969/announce',
  'udp://tracker.srv00.com:6969/announce',
  'udp://tracker.torrent.eu.org:451/announce',
  'udp://tracker2.dler.com:80/announce',
  'udp://tracker6.lelux.fi:6969/announce',
  'udp://u4.trakx.crim.ist:1337/announce',
  'udp://u6.trakx.crim.ist:1337/announce',
  'udp://uploads.gamecoast.net:6969/announce',
  'udp://v1046920.hosted-by-vdsina.ru:6969/announce',
  'udp://wepzone.net:6969/announce',
  'udp://www.peckservers.com:9000/announce'
]
let trackerSet = new Set(trackerList)
let peers = new Set()

const udpSend = (socket, message, callback = () => {}) => {
  trackerSet.forEach((trackerUrl) => {
    const urlObj = url.parse(trackerUrl)
    if (urlObj.protocol === 'udp:') {
      socket.send(
        message,
        0,
        message.length,
        urlObj.port,
        urlObj.hostname,
        callback
      )
    }
  })
  reqTimes++

  if (timer) {
    clearTimeout(timer)
  }
  timer = setTimeout(() => {
    if (reqTimes >= 8) {
      console.log('Request faild!')
      process.exit()
    }
    console.log(`No response, try ${reqTimes}...`)
    udpSend(socket, message)
  }, 15000)
}

module.exports = {
  async getPeers(torrent, callback) {
    const socket = dgram.createSocket('udp4')

    if (torrent.announce) {
      trackerSet.add(torrent.announce.toString('utf8'))
    }
    if (torrent['announce-list']) {
      for (let element of torrent['announce-list']) {
        for (let announce of element) {
          trackerSet.add(announce.toString('utf8'))
        }
      }
    }

    socket.on('message', (res) => {
      clearTimeout(timer)
      reqTimes = 0

      const action = res.readUInt32BE(0)
      if (action === 0) {
        // connectRes
        // console.log(`Get connect response.`)

        const connectRes = messageBuilder.connectRes(res)
        const trackerReq = messageBuilder.trackerReq(
          connectRes.connectionId,
          torrent
        )

        // console.log('Send tracker request.')
        udpSend(socket, trackerReq)
      } else if (action === 1) {
        // trackerRes
        // console.log(`Get tracker response.`)

        const trackerRes = messageBuilder.trackerRes(res)

        let newPeers = []
        trackerRes.peers.forEach((peer) => {
          if (!peers.has(peer)) {
            newPeers.push(peer)
            peers.add(peer)
          }
        })
        callback(newPeers)
      }
    })

    // console.log('Send connect request.')
    udpSend(socket, messageBuilder.connectReq())
  }
}
